import {Logger} from "./logger";
import express, {
    Express,
    NextFunction as ExpressNextFunction,
    Request as ExpressRequest,
    Response as ExpressResponse,
} from "express";
import path from "path";
import "reflect-metadata";
import {
    ArgumentsHost,
    defineModule,
    DESIGN_PARAMTYPES,
    INJECTED_TOKENS,
    RequestMethod,
    GlobalHttpExceptionFilter, DECORATOR_FACTORY, PipeTransform, ExecutionContext, CanActivate,
    ForbiddenException, NestInterceptor
} from '@nestjs/common'
import {Reflector} from './reflector'
import {getIPAddress} from '@nestjs/tools';
import {APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE, FORBIDDEN_RESOURCE} from "./constant";
import {from, mergeMap, Observable, of} from "rxjs";

export class NestApplication {
    // 内部私有化一个Express实例
    private readonly app: Express = express();
    // 保存所有的provider的实例，key就是token，值是实例或者值
    private readonly providerInstances = new Map();
    // 此处存放着全局可用的提供者和token
    private readonly globalProviders = new Set();
    // 记录每个模块里都有哪些token和provider
    private readonly moduleProviders = new Map();
    // 记录所有的中间件 可能是类，可能是类的实例，可能是中间件函数
    private readonly middlewares = [];
    // 记录所有要排除的中间件路径
    private readonly excludeRoutes = [];
    // 添加一个全局的异常过滤器
    private readonly defaultGlobalHttpExceptionFilter = new GlobalHttpExceptionFilter();
    // 存放所有的全局异常过滤器
    private readonly globalHttpExceptionFilter = [];
    // 存放全局的管道pipes
    private readonly globalPipes: PipeTransform[] = [];
    // 存放全局的守卫guards
    private readonly globalGuards: CanActivate[] = [];
    // 存放全局的拦截器interceptors
    private readonly globalInterceptors: NestInterceptor[] = [];

    constructor(protected readonly module: any) {
        // 处理不同格式参数 存放body的中间件
        this.app.use(express.json())    //用来吧json格式的请求体对象放在req.body中
        // @ts-ignore
        this.app.use(express.urlencoded({extends: true})) //吧form表单格式的请求对象放在req.body
        this.app.use((req, res, next) => {
            req['user'] = {name: 'admin', role: 'admin'}
            next()
        })
    }

    // 全局拦截器
    useGlobalInterceptors(...interceptors: NestInterceptor[]) {
        this.globalInterceptors.push(...interceptors);
    }

    useGlobalGuards(...guards: CanActivate[]) {
        this.globalGuards.push(...guards);
    }

    useGlobalFilters(...filters) {
        defineModule(this.module, filters.filter((filter) => filter instanceof Function));
        this.globalHttpExceptionFilter.push(...filters);
    }

    useGlobalPipes(...pipes: PipeTransform[]) {
        this.globalPipes.push(...pipes);
    }

    private initMiddlewares() {
        // 调用中间件的方法，MiddlewareConsumer就是当前NestApplication的实例
        this.module.prototype.configure?.(this);
    }

    apply(...middleware) {
        // 把接受的到的中间件放到中间的数组中，并且返回当前的实例
        defineModule(this.module, middleware);
        this.middlewares.push(...middleware);
        return this;
    }

    forRoutes(...routes) {
        // 循环路径信息，
        for (const route of routes) {
            // 遍历中间件
            for (const middleware of this.middlewares) {
                const {routePath, routeMethod} = this.normalizeRouteInfo(route);
                // use方法的第一个参数就表示匹配的路径，没有匹配的就不执行回调函数
                this.app.use(routePath, (req, res, next) => {

                    if (this.isExcluded(req.originalUrl, req.method)) {
                        return next();
                    }

                    // 如果配置的方法名是ALL 或者 方法名完全匹配
                    if (routeMethod === RequestMethod.ALL || routeMethod === req.method) {
                        // 此处middleware可能是一个类，可能是一个实例，也可能是一个函数
                        // middleware都需要实现NestMiddleware接口，它包含use方法以此来判断
                        if ('use' in middleware.prototype || 'use' in middleware) {
                            const middlewareInstance = this.getMiddlewareInstance(middleware);
                            middlewareInstance.use(req, res, next)
                        } else if (middleware instanceof Function) {
                            middleware(req, res, next)
                        } else {
                            next();
                        }
                    } else {
                        next();
                    }
                })
            }
        }

        // 链式操作，.apply .forRoutes是一对的只针对apply之后的routes
        this.middlewares.length = 0;
        return this;
    }

    exclude(...routeInfos) {
        this.excludeRoutes.push(...routeInfos.map(this.normalizeRouteInfo));
        return this;
    }

    private isExcluded(reqPath: string, method: string) {
        // 遍历要排除的路径，看看哪一个排除的路径和当前的请求路径和方法名匹配
        return this.excludeRoutes.some((routeInfo) => {
            const {routePath, routeMethod} = routeInfo;
            return routePath === reqPath && (routeMethod === method || routeMethod === RequestMethod.ALL);
        })
    }

    private normalizeRouteInfo(route) {
        let routePath = '';
        let routeMethod = RequestMethod.ALL;  //默认支持所有方法
        if (typeof route === 'string') {
            routePath = route;
        } else if ('path' in route) {
            // 如果传入的是一个路径对象
            routePath = route.path;
            routeMethod = route.method ?? RequestMethod.ALL;
        } else if (route instanceof Function) {
            // 如果route是一个controller控制器，以它的路径作为前缀
            routePath = Reflect.getMetadata('prefix', route)
        }
        //  cats ==> /cats
        routePath = path.posix.join('/', routePath);
        return {routePath, routeMethod}
    }

    private getMiddlewareInstance(middleware) {
        if (middleware instanceof Function) {
            // 解析这个中间件的依赖项
            const dependencies = this.resolveDependencies(middleware);
            return new middleware(...dependencies)
        }
        return middleware
    }

    use(middleware) {
        this.app.use(middleware)
    }

    // 配置初始化工作
    async initController(module) {
        // 去除模块里所有的控制器，做好路由映射配置
        const controllers = Reflect.getMetadata("controllers", module) ?? [];
        Logger.log(`AppModule dependencies initialized`, "InstanceLoader");

        // 为什么循环 controllers就能拿到类了，因为module装饰器该参数存放的就是类
        for (const Controller of controllers) {

            // 创建controller 类的构造方法参数
            const dependencies = this.resolveDependencies(Controller);

            // 创建每个控制器的实例
            const controller = new Controller(...dependencies);
            // 获取控制器的前缀
            let prefix = Reflect.getMetadata("prefix", Controller) || "/";
            Logger.log(`${Controller.name} {${prefix}}`, "RoutesResolver");

            // 获取每个类方法的元数据，用来映射路由
            // const propertyKeys = Object.getOwnPropertyNames(Reflect.getPrototypeOf(controller)); //获取 controller实例对象原型，在获取他的方法名字
            const ControllerPrototype = Controller.prototype;
            const propertyKeys = Object.getOwnPropertyNames(ControllerPrototype);

            // 获取控制器上绑定的异常过滤器数组
            const controllerFilters = Reflect.getMetadata('filters', Controller) ?? []
            defineModule(this.module, controllerFilters);

            // 获取控制器上绑定的元数据pipes，管道数组
            const controllerPipes = Reflect.getMetadata('pipes', Controller) ?? [];

            // 获取控制器上的守卫 guards
            const controllerGuards = Reflect.getMetadata('guards', Controller) ?? [];

            // 获取控制器上的拦截器
            const controllerInterceptors = Reflect.getMetadata('interceptors', Controller) ?? [];

            for (const methodKey of propertyKeys) {
                // 获取实例方法函数
                let method = ControllerPrototype[methodKey];
                // 通过类创建时，装饰器的元数据和方法函数method获取元数据，用来做路由映射
                let HTTPpath = Reflect.getMetadata("path", method);
                let HTTPmethod = Reflect.getMetadata("method", method);
                let redirectUrl = Reflect.getMetadata("redirectUrl", method);
                let redirectStatusCode = Reflect.getMetadata("redirectStatusCode", method);
                let statusCode = Reflect.getMetadata('statusCode', method);
                let headers = Reflect.getMetadata('headers', method) ?? [];
                // 获取方法上的异常过滤器数组
                const methodFilters = Reflect.getMetadata('filters', method) ?? []
                defineModule(this.module, methodFilters);

                // 获取控制器中方法上绑定的元数据pipes，管道数组
                const methodPipes = Reflect.getMetadata('pipes', method) ?? [];
                // 合并管道
                const pipes = [...controllerPipes, ...methodPipes]

                // 获取控制器中方法的守卫，guards
                const methodGuards = Reflect.getMetadata('guards', method) ?? [];
                // 合并守卫
                const guards = [...this.globalGuards, ...controllerGuards, ...methodGuards];

                // 获取方法上的拦截器
                const methodInterceptors = Reflect.getMetadata('interceptors', method) ?? [];
                // 合并所有拦截器
                const interceptors = [...this.globalInterceptors, ...controllerInterceptors, ...methodInterceptors];

                if (!(HTTPpath && HTTPmethod)) {
                    continue;
                }
                // 拼接完整的路径
                const routerPath = path.posix.join("/", prefix, HTTPpath);
                await this.app[HTTPmethod.toLowerCase()](routerPath, async (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => {
                    const ctx: ArgumentsHost = {       //为什么这么些？因为她不但支持http，还支持graphql 微服务 websocket 封装了一层统一的
                        // @ts-ignore
                        switchToHttp() {
                            return {
                                getRequest: () => req,
                                getResponse: () => res,
                                getNext: () => next
                            }
                        }
                    }
                    const context: ExecutionContext = {
                        ...ctx,
                        getClass: () => Controller,
                        getHandler: () => method
                    }
                    try {
                        await this.callGuards(guards, context);
                        // 参数装饰器
                        // const args = await this.resolveParams(controller, methodKey, context, ctx, pipes);
                        this.cellInterceptors(controller, method, interceptors, context, ctx, pipes).subscribe({
                            next: (result) => {
                                // // 指向路由处理函数，获取返回值
                                // const result = await method.call(controller, ...args);
                                // 判断如果需要重定向，则直接重定向到指定的redirectUrl
                                if (redirectUrl) {
                                    return res.redirect(redirectStatusCode || 302, redirectUrl)
                                }
                                if (result?.url) {
                                    return res.redirect(result?.statusCode || 302, result?.url)
                                }
                                if (statusCode) {
                                    res.statusCode = statusCode;
                                } else if (HTTPmethod === 'POST') {
                                    res.statusCode = 201;
                                }
                                // 处理 参数装饰器 @Res @Response
                                // 获取方法参数装饰器的元数据,判断方法元数据是否含有 Response 和 Res
                                // tip: 为了与底层 HTTP 平台（例如 Express 和 Fastify）之间的类型兼容，Nest 提供了 @Res() 和 @Response() 装饰器。 @Res() 只是@Response() 的别名。两者都直接公开底层本机平台响应对象接口。使用它们时，您还应该导入底层库的类型（例如@types/express）以充分利用它们。
                                // 请注意，当您在方法处理程序中注入 @Res() 或 @Response() 时，您会将 Nest 置于该处理程序的库特定模式中，并且您将负责管理响应。执行此操作时，您必须通过调用响应对象（例如 res.json(...) 或 res.send(...)）来发出某种类型的响应，否则 HTTP 服务器将挂起。

                                // 判断controller的metadaKey方法里有没有使用Response或Res，如果用了任何一个不发送响应
                                const responseMeta = this.getResponseMetadate(controller, methodKey);
                                // 或者没有注入Response参数装饰器，或者注入了但是传递了passthrough参数，都会有nestjs来返回相应
                                // 如果使用了Next也会挂起
                                if (!responseMeta || (responseMeta?.data?.passthrough)) {
                                    headers.map(({name, value}) => {
                                        res.setHeader(name, value);
                                    })
                                    // 把返回值序列化发回给浏览器 、 客户端
                                    res.send(result);
                                }
                            },
                            error: (error) => {
                                this.callExceptionFilters(error, ctx, controllerFilters, methodFilters);
                            }
                        })
                    } catch (error) {
                        await this.callExceptionFilters(error, ctx, controllerFilters, methodFilters);
                    }
                });
                Logger.log(
                    `Mapped {${routerPath}, ${HTTPmethod}} router`,
                    "RouterExplorer"
                );
            }
        }
    }

    // 绑定守卫的方法
    private cellInterceptors(
        controller, method,
        // args,
        interceptors, context, ctx, pipes
    ) {
        const nextFn =  (i: number = 0): Observable<any> => {
            if (i >= interceptors.length) {
                return from(this.resolveParams(controller, method.name, context, ctx, pipes)).pipe(
                    mergeMap((args)=>{
                        const result = method.call(controller, ...args)
                        return result instanceof Promise ? from(result) : of(result)
                    })
                )
            }
            const handler = {
                handle: () => {
                    return nextFn(i + 1)
                }
            }
            const interceptor = this.getInterceptorInstance(interceptors[i]);
            const result = interceptor.intercept(context, handler);
            return from(result).pipe(mergeMap((res) => res instanceof Observable ? res : of(res)));
        }
        return nextFn();
    }

    private getInterceptorInstance(interceptor): any {
        if (typeof interceptor === 'function') {
            const dependencies = this.resolveDependencies(interceptor);
            return new interceptor(...dependencies)
        }
        return interceptor;
    }

    // 绑定守卫的方法
    private async callGuards(guards: CanActivate[], context: ExecutionContext) {
        for (const guard of guards) {
            const guardInstance = this.getGuardInstance(guard)
            const canActive = guardInstance.canActivate(context);
            if (!canActive) {
                throw new ForbiddenException(FORBIDDEN_RESOURCE);
            }
        }
    }

    // 获取守卫的实例，判断已经是实例还是是类，最终实例出
    private getGuardInstance(guard: (CanActivate | (new (...args: any[]) => CanActivate))) {
        if (guard instanceof Function) {
            // 解析这个中间件的依赖项
            const dependencies = this.resolveDependencies(guard);
            return new guard(...dependencies)
        }
        return guard
    }

    private getFilterInstance(filter) {
        if (filter instanceof Function) {
            // 解析这个中间件的依赖项
            const dependencies = this.resolveDependencies(filter);
            return new filter(...dependencies)
        }
        return filter
    }

    private async callExceptionFilters(error, host, controllerFilters, methodFilters) {
        // 按照：方法过滤器，控制器过滤器，用户配置全局过滤器，默认过滤器顺序，找到第一个能处理这个错误的过滤器进行处理就可以了
        const allFilters = [
            ...methodFilters,
            ...controllerFilters,
            ...this.globalHttpExceptionFilter,
            this.defaultGlobalHttpExceptionFilter
        ];
        for (const filter of allFilters) {
            let filterInstance = this.getFilterInstance(filter);
            // 取出此异常过滤器关心的异步或者说要处理的异常
            const exceptions = Reflect.getMetadata('catch', filterInstance.constructor) ?? [];
            // 如果没有配置catch，或者说当前的错误刚好就是配置的catch的exception的类型或者说他的子类
            if (exceptions.length === 0 || exceptions.some(exception => error instanceof exception)) {
                filterInstance.catch(error, host);
                break;
            }
        }
    }

    private async resolveParams(
        instance: any,
        methodKey: string,
        context,
        host,
        pipes: PipeTransform[]
    ) {
        const {getRequest, getResponse, getNext} = context.switchToHttp()
        const req = getRequest();
        const res = getResponse();
        const next = getNext();
        // 获取参数的元数据
        const paramsMetadata = Reflect.getMetadata("params", instance, methodKey) ?? [];
        return Promise.all(paramsMetadata.map(async (itemParamMetaData) => {
            // 方法参数的管道pipes
            const {key, data, factory, pipes: paramPipes, metatype} = itemParamMetaData;
            let value;
            switch (key) {
                case "Request":
                case "Req":
                    value = req;
                    break;
                case "Query":
                    value = data ? req.query[data] : req.query;
                    break;
                case "Headers":
                    value = data ? req.headers[data] : req.headers;
                    break;
                case "Session":
                    value = data ? req['session'][data] : req['session'];
                    break;
                case "Ip":
                    value = req.ip
                    break;
                case "Param":
                    value = data ? req.params[data] : req.params
                    break;
                case "Body":
                    value = data ? req.body[data] : req.body
                    break;
                case "Response":
                case "Res":
                    value = res
                    break;
                case "Next":
                    value = next
                    break;
                case "UploadedFile":
                    value = req.file;
                    break;
                case "UploadedFiles":
                    break;
                case DECORATOR_FACTORY:
                    value = factory(data, host);
                    break;
                default:
                    value = null;
                    break;
            }
            // 合并控制器方法管道 和 方法参数上的管道
            for (const pipe of [...this.globalPipes, ...pipes, ...paramPipes]) {
                const pipeInstance = this.getPipeInstance(pipe);
                let type = key === DECORATOR_FACTORY ? 'custom' : key.toLowerCase();
                value = await pipeInstance.transform(value, {
                    type: type,
                    metatype: metatype,        //下次讲解，用于校验原参数类型 value:string的这个string
                    data: data
                });
            }
            return value;
        }));
    }

    private getPipeInstance(pipe) {
        if (typeof pipe === 'function') {
            const dependencies = this.resolveDependencies(pipe);
            return new pipe(...dependencies);
        }
        return pipe;
    }

    getResponseMetadate(controller, methodKey): Record<string, any> {
        let metadataKeys = Reflect.getMetadata('params', controller, methodKey) ?? [];
        return metadataKeys.find((item) => item.key === 'Res' || item.key === 'Response' || item.key === 'Next')
    }

    private async addDefaultProviders() {
        // 注册系统内部默认的provider，一些提供者
        this.addProvider(Reflector, this.module, true);
    }

    // 初始AppModule供应商的类存储为map
    private async initProviders() {
        // nestjs内部维护的provider
        await this.addDefaultProviders();

        // 重写注册providers流程
        //! 1.拿到导入的模块元数据
        const imports = Reflect.getMetadata('imports', this.module) ?? [];
        // 2. 循环所有的导入模块
        for (const importModule of imports) {
            let ImportModule_ = importModule;
            // 如果导入的是一个Promise，说明态势异步的动态模块
            if (importModule instanceof Promise) {
                ImportModule_ = await importModule;
            }

            // 动态模块：如果导入的模块有module属性，说明这是一个动态模块，否则则是普通模块
            if ('module' in ImportModule_) {
                const {module, providers, exports, controllers} = ImportModule_;
                // 把老的和新的providers和exports进行合并
                const oldProviders = Reflect.getMetadata('providers', module)
                const newProviders = [...(oldProviders ?? []), ...(providers ?? [])];
                const oldExports = Reflect.getMetadata('exports', module)
                const newExports = [...(oldExports ?? []), ...(exports ?? [])];
                const oldControllers = Reflect.getMetadata('controllers', module);
                const newControllers = [...(oldControllers ?? []), ...(controllers ?? [])];
                defineModule(module, newProviders);
                defineModule(module, newControllers);
                Reflect.defineMetadata('providers', newProviders, module);
                Reflect.defineMetadata('exports', newExports, module);
                Reflect.defineMetadata('controllers', newControllers, module);
                this.registerProvidersFromModule(module, this.module);
            } else {
                this.registerProvidersFromModule(ImportModule_, this.module);
            }
        }
        // 当前模块提供的元数据appModule的providers
        const providers = Reflect.getMetadata('providers', this.module) ?? [];
        for (const provider of providers) {
            this.addProvider(provider, this.module);
        }
    }

    private async registerProvidersFromModule(importModule, ...parentModules) {
        // 获取导入的模块是不是全局模块
        const global = Reflect.getMetadata('global', importModule);
        // 闹到导入模块provider进行全量注册
        const importedProviders = Reflect.getMetadata('providers', importModule) ?? [];
        // 1.1 有可能导入的模块只导出了一部分，并没有全量导出，所以需要使用exports进行过滤
        const exports = Reflect.getMetadata('exports', importModule) ?? [];
        // 1.2 循环导出exports数组
        for (const exportToken of exports) {
            // 2.exports内还有可能存在module
            if (this.isModule(exportToken)) {
                // 要执行递归操作
                // A模块引用B模块，B模块导入导出C模块，C模块导入并导出D模块，D模块里有一个exports[DService]
                // A B C D模块都可以使用DService
                this.registerProvidersFromModule(exportToken, importModule, ...parentModules)
            } else {
                // 判断provider每一项的token是否和 exports的导出项一致如果是则表示重新导出
                // 执行addProvider将 provider实例化添加到providers map中
                const provider = importedProviders.find((provider) => {
                    return (provider === exportToken) || (provider.provide === exportToken)
                });
                if (provider) {
                    // 遍历数组
                    [importModule, ...parentModules].forEach((module) => {
                        this.addProvider(provider, module, global);
                    })
                }
            }
        }
        await this.initController(importModule)
    }

    // 将providers中的每一项 实例化出对象并添加到 this.providers中

    private addProvider(provider, module, global = false) {
        /*
         * 原来的provider都在一起，没有隔离
         * 现在需要分开，每个模块都有自己的provider
         * **/
        // 这个provider代表module这个模块对应的provider的token
        // providers仔global为true的情况下就是this.globalProviders set
        // providers仔global为false的情况下module对应的providers set
        const providers = global ? this.globalProviders : (this.moduleProviders.get(module) || new Set());
        // set本身就可以去重，不需要添加判断
        if (!global) {
            this.moduleProviders.set(module, providers);
        }
        // 为了避免循环依赖，每次添加前做一个判断，如果map中已经存在则不执行
        // 1.获取要注册的providerToken
        let injectToken = provider.provide ?? provider;
        // 2.判断,如果实例已经有了实例，则不继续创建实例，直接存放依赖map集合
        if (this.providerInstances.has(injectToken)) {
            providers.add(injectToken);
            return;
        }

        // 如果AppModule providers有参数这样传递，说明是类
        if (provider.provide && provider.useClass) {
            const dependencies = this.resolveDependencies(provider.useClass);
            // 创建类的实例
            const classInstance = new provider.useClass(...dependencies);      //此处尚未完成，因为这个类可能还会有依赖
            // 吧provider的token和类保存到this.providers中
            this.providerInstances.set(provider.provide, classInstance);
            providers.add(provider.provide);
        } else if (provider.provide && provider.useValue) {
            // 提供的是一个值，则不需要容器辅助实例化，直接注册就可以了
            this.providerInstances.set(provider.provide, provider.useValue)
            providers.add(provider.provide);
        } else if (provider.provide && provider.useFactory) {
            // 工厂函数的方式
            const inject = provider.inject ?? [];
            const injectValue = inject.map((injectToken) => this.getProviderByToken(injectToken, module));
            this.providerInstances.set(provider.provide, provider.useFactory(...injectValue))
            providers.add(provider.provide);
        } else {
            // 表示只提供了一个类，token是这个类，值是这个类的实例
            const dependencies = this.resolveDependencies(provider);
            this.providerInstances.set(provider, new provider(...dependencies));
            providers.add(provider);
        }
    }

    // 判断exportToken元数据是否包含module数组
    private isModule(exportToken) {
        return exportToken && exportToken instanceof Function && Reflect.getMetadata('isModule', exportToken);
    }

    // 获取providers key的实例
    private getProviderByToken = (injectedToken, module) => {
        // 如何通过token在特定模块下找对应的provider
        // 先找到此模块对应的token set集合，在判断injectedToken在不在此set中
        // 如果存在，则肯能返回对应的provider实例
        if (this.moduleProviders.get(module)?.has(injectedToken)) {
            return this.providerInstances.get(injectedToken);
        } else if (this.globalProviders.has(injectedToken)) {      //判断全局的有没有该token有的获取并返回
            return this.providerInstances.get(injectedToken);
        } else {
            return null;
        }
    }

    // 获取构类的构造的参数和injectTokens元数据去映射 注入的类去实例
    private resolveDependencies(Controller) {
        // 获取类的元数据
        const injectedTokens = Reflect.getMetadata(INJECTED_TOKENS, Controller) ?? [];
        // 获取构造函数的参数类型
        const constructorParams = Reflect.getMetadata(DESIGN_PARAMTYPES, Controller) ?? [];
        return constructorParams.map((param, index) => {
            // 把每个param中的token默认换成对应的provider值
            // 如果使用的装饰器 Inject则使用它没有则使用，构造函数的参数
            const module = Reflect.getMetadata('nestModule', Controller);
            return this.getProviderByToken(injectedTokens[index] ?? param, module);
        })
    }

    async initGlobalFilters() {
        const providers = Reflect.getMetadata('providers', this.module) ?? [];
        for (const provider of providers) {
            if (provider.provide === APP_FILTER) {
                const providerInstance = this.getProviderByToken(APP_FILTER, this.module);
                this.useGlobalFilters(providerInstance);
            }
        }
    }

    private async initGlobalPipes() {
        const providers = Reflect.getMetadata('providers', this.module) ?? [];
        for (const provider of providers) {
            if (provider.provide === APP_PIPE) {
                const providerInstance = this.getProviderByToken(APP_PIPE, this.module);
                this.useGlobalPipes(providerInstance);
            }
        }
    }

    private async initGlobalGuards() {
        const providers = Reflect.getMetadata('providers', this.module) ?? [];
        for (const provider of providers) {
            if (provider.provide === APP_GUARD) {
                const providerInstance = this.getProviderByToken(APP_GUARD, this.module);
                this.useGlobalGuards(providerInstance);
            }
        }
    }

    private async initGlobalInterceptors() {
        const providers = Reflect.getMetadata('providers', this.module) ?? [];
        for (const provider of providers) {
            if (provider.provide === APP_INTERCEPTOR) {
                const interceptor = this.getProviderByToken(APP_INTERCEPTOR, this.module);
                this.useGlobalInterceptors(interceptor);
            }
        }
    }

    // 启动HTTP服务
    async listen(port) {
        await this.initProviders();       //注册providers
        // 给实例添加中间件
        this.initMiddlewares();     //初始化中间件配置
        await this.initGlobalFilters();     //初始化全局的过滤器
        await this.initGlobalPipes();       // 初始化全局pipe providers-APP_PIPE 该方式可以使用注入provide
        await this.initGlobalGuards();      // 初始化全局守卫 guards
        await this.initGlobalInterceptors();    // 初始化全局拦截器
        await this.initController(this.module);

        // 调用express实例的listen方法，启动一个HTTP服务器，监听port端口
        this.app.listen(port, () => {
            Logger.log(
                `Application is running on http://localhost:${port}`,
                "NestApplication"
            );
            Logger.log(
                `Application is running on http://${getIPAddress()}:${port}`,
                "NestApplication"
            )
        });
    }
}
